/**
 * 在内置工具类型中，对 模式匹配工具类型（回顾：16_工具类型_5、模式匹配工具类型.ts） 的进阶：
 * 只有深层嵌套这么一种，特殊位置的 infer 处理其实大部分时候也是通过深层嵌套实现
*/

//下面是模式匹配中常用的一种方法，
//通过 infer 提取到某一个结构，然后再对这个结构进行 infer 提取。
//通过 infer 提取到某一个结构，然后再对这个结构进行 infer 提取。

//1、比如此前我们实现了提取函数的首个参数类型：
type FunctionType = (...args: any) => any;
type FirstParameter<T extends FunctionType> = T extends (
    arg: infer P,
    ...args: any
) => any
    ? P
    : never;

//2、提取最后一个参数类型则可以这样：
type LastParameter<T extends FunctionType> = T extends (arg: infer P) => any
    ? P
    : T extends (...args: infer R) => any
    ? R extends [...any, infer Q]
    ? Q
    : never
    : never;

type FuncFoo = (arg: number) => void;
type FuncBar = (...args: string[]) => void;
type FuncBaz = (arg1: string, arg2: boolean) => void;

type FooLastParameter = LastParameter<FuncFoo>; // number
type BarLastParameter = LastParameter<FuncBar>; // string
type BazLastParameter = LastParameter<FuncBaz>; // boolean

/**
 * 在 “15_类型里的逻辑运算_2、infer 关键字” 中，介绍一个提取 Promise 内部值类型的工具类型 PromiseValue， 
 * 在 TypeScript 内置工具类型 中也存在这么一个作用的工具类型，并且它的实现要更为严谨：
 * 
 * 在这里 Awaited 并非通过 Promise<infer V> 来提取函数类型，
 * 而是通过 Promise.then 方法提取，
 * 首先提取到 then 方法中的函数类型，
 * 再通过这个函数类型的首个参数来提取出实际的值。
 * */

type Awaited<T> = T extends null | undefined
    ? T
    : T extends object & { then(onfulfilled: infer F): any }
    ? F extends (value: infer V, ...args: any) => any
    ? Awaited<V>
    : never
    : T;

type PromiseValueResult1 = Awaited<Promise<string | number>>; //string | number

//export {}：解决“无法重新声明块范围变量”错误提示问题
export { }